<?php

namespace adminApi\behaviors;

use adminApi\models\db\Adminers;
use Carbon\Carbon;
use common\components\fast_api\ApiException;
use common\components\wtools\tools\ArrayHelper;
use common\components\wtools\tools\Security;
use common\datas\Enums;
use common\Tools;
use yii\base\ActionFilter;
use yii2mod\query\ArrayQuery;

class JwtTokenCheck extends ActionFilter
{
    public static function getRouteAccessDatas()
    {
        $datas = [
            ['permission' => '权限管理', 'route' => null],
            ['permission' => '权限管理-管理员列表', 'route' => 'rbac/adminer/list'],
            ['permission' => '权限管理-添加管理员', 'route' => 'rbac/adminer/add-or-edit'],
            ['permission' => '权限管理-修改管理员', 'route' => 'rbac/adminer/add-or-edit'],
            ['permission' => '权限管理-角色列表', 'route' => 'rbac/role/list'],
            ['permission' => '权限管理-添加角色', 'route' => 'rbac/role/add-or-edit'],
            ['permission' => '权限管理-修改角色', 'route' => 'rbac/role/add-or-edit'],
            ['permission' => '商品库-分类管理', 'route' => 'product/category/list'],
            ['permission' => '商品库-分类管理', 'route' => 'product/category/add-or-edit'],
            ['permission' => '商品库-分类管理', 'route' => 'product/category/del'],
            ['permission' => '商品库-供应商管理', 'route' => 'product/supplier/list'],
            ['permission' => '商品库-供应商管理', 'route' => 'product/supplier/add-or-edit'],
            ['permission' => '商品库-商品管理', 'route' => 'product/goods/list'],
            ['permission' => '商品库-商品管理-商品列表', 'route' => 'product/goods/list'],
            ['permission' => '商品库-商品管理-商品详细', 'route' => 'product/goods/info'],
            ['permission' => '商品库-商品管理-添加商品', 'route' => 'product/goods/add-or-edit'],
            ['permission' => '商品库-商品管理-修改商品', 'route' => 'product/goods/add-or-edit'],
            ['permission' => '商品库-商品管理-复制商品', 'route' => 'product/goods/add-or-edit'],
        ];
        return $datas;
    }

    public static function getAuthRoutes()
    {
        $query = new ArrayQuery();
        $query->from(self::getRouteAccessDatas());
        $query->andWhere(['!=', 'route', null]);
        $routeDatas =  $query->all();
        $routes = [];
        foreach ($routeDatas as $k => $v) {
            if (!in_array($v['route'], $routes)) {
                $routes[] = $v['route'];
            }
        }
        return $routes;
    }

    public function beforeAction($action)
    {
        $request = \Yii::$app->request;
        $params = $request->post();
        if (isset($params['token'])) {
            ApiException::throwError(201808161402, 'token请在header里请求，否则会有安全隐患');
        }
        $jwtToken = $request->headers->get('authorization');
        $jwtToken = str_replace("Bearer ", "", $jwtToken);
        if (!$jwtToken) {
            ApiException::throwError(201801010000, 'token未找到');
        }
        if (isset($params['key'])){
            ApiException::throwError(201808161401, '请不要传key，会有安全隐患');
        }
        $jwtTokenArr = ArrayHelper::str2arr($jwtToken, '.');
        $payloadArr = Tools::isJson(base64_decode($jwtTokenArr[1]));
        if ($payloadArr['end_at'] < Carbon::now()->timestamp) {
            ApiException::throwError(201808161404, '认证已过期');
        }
        $token = Security::thinkDecrypt($payloadArr['token'], \Yii::$app->params['jwt']['adminApi']['jwtThinkKey']);
        if (strlen($token) != 42) {
            ApiException::throwError(201808161403, '认证口令失效', \Yii::$app->params['jwt']['adminApi']['reLoginStatusCode']);
        }else{
            $token = substr($token, 0, 32);
            $adminer = Adminers::findIdentityByAccessToken($token);
        }
        if (!$adminer){
            ApiException::throwError(201808161456, "没有找到用户,请重新登陆");
        }
        if (\Yii::$app->params['isCheckTime']) {
            if (!isset($params['timestamp'])) {
                ApiException::throwError(201808161406, '请求必须有当前操作时间戳');
            }
            if (strlen($params['timestamp']) != 10) {
                ApiException::throwError(201808161407, '时间戳长度必须为10位秒数');
            }
            if (abs(substr($params['timestamp'], 0, 10) - Carbon::now()->timestamp) > 600){
                ApiException::throwError(201808161408, '操作超时或时间异常，请检查设备时间');
            }
        }
        if (\Yii::$app->params['isCheckNonce']) {
            if (!isset($params['nonce'])) {
                ApiException::throwError(201808161409, '请求必须设置随机数');
            }
            if (strlen($params['nonce']) < 9 || strlen($params['nonce']) > 181) {
                ApiException::throwError(201808161411, '随机数长度错误');
            }
            $nonce_key = APP_ID.'/nonceAdminer/'.$adminer->id;
            $tmp_nonces = is_array(\Yii::$app->cache->get($nonce_key))?\Yii::$app->cache->get($nonce_key):[];
            if (!in_array($params['nonce'], $tmp_nonces)){
                $tmp_nonces[] = $params['nonce'];
                if (count($tmp_nonces) > 10000) {
                    array_shift($tmp_nonces);
                }
                \Yii::$app->cache->set($nonce_key, $tmp_nonces, 3600 * 25);
            }else{
                ApiException::throwError(201808161412, '请求随机数重复');
            }
        }
        if (\Yii::$app->params['isCheckSign']) {
            if (!isset($params['sign'])) {
                ApiException::throwError(201808161404, '请求必须有请求签名');
            }
            if (strlen($params['sign'])!=32) {
                ApiException::throwError(201808161405, '请求签名长度错误');
            }
            $p = $params;
            $p['token'] = $payloadArr['token'];
            $p['key'] = md5($adminer->key.$payloadArr['created_at']);
            ksort($p);
            unset($p['sign']);
            $p_str = Tools::toQuery($p);
//            Tools::wolog($p_str, 'checkSign');
            $_sign = md5($p_str);
            if ($_sign != $params['sign']){
                ApiException::throwError(201808161457, "验签失败");
            }
        }
        if ($adminer->status != Enums::ACTIVE){
            ApiException::throwError(201808161456, "用户状态异常，如果你被禁了，请联系管理员");
        }
        if ($adminer->is_super !== Enums::YES && in_array($action->controller->route, self::getAuthRoutes())) {
            if (!isset($params['permissionName'])) {
                ApiException::throwError(202408031730, '权限名必传');
            }
            $permission = $params['permissionName'];
            $authRoute = (new ArrayQuery())->from(self::getRouteAccessDatas())
                ->andWhere(['route' => $action->controller->route])
                ->andWhere(['permission' => $permission])
                ->one();
            if (!$authRoute) {
                ApiException::throwError(202408031724, '未找到对应权限');
            }
            if (!in_array($permission, $adminer->permissionPaths)) {
                ApiException::throwError(202408031807, '无权访问', \Yii::$app->params['jwt']['adminApi']['reLoginStatusCode']);
            }
        }
        \Yii::$app->user->login($adminer);
        return parent::beforeAction($action);
    }
}
